www.gusucode.com > VC++ 多种窗体动画特效源码-源码程序 > VC++ 多种窗体动画特效源码-源码程序/code/VisualFx.cpp
/*############################################################################# # VISUALFX.CPP # Download by http://www.NewXing.com # SCA Software International S.A. # http://www.scasoftware.com # scaadmin@scasoftware.com # # Copyright (c) 1999 SCA Software International S.A. # # Date: 03.01.2000 # Author: Zoran M.Todorovic # # This software is provided "AS IS", without a warranty of any kind. # You are free to use/modify this code but leave this header intact. # #############################################################################*/ #include "stdafx.h" #include <afxpriv.h> // Needed for WM_SIZEPARENT #include "VisualFx.h" #ifdef _DEBUG #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #ifdef _DEBUG #define new DEBUG_NEW #endif //============================================================================= // class TTabItem // //============================================================================= // Create a tab item TTabItem::TTabItem(CWnd *pParent, LPCTSTR szLabel) { m_pWnd = NULL; m_nMinX = m_nMaxX = 0; m_bVisible = TRUE; m_bEnabled = TRUE; m_bWndEnabled = TRUE; RECT rect; ::ZeroMemory(&rect,sizeof(RECT)); m_pCaption = new CStatic; ASSERT(m_pCaption); m_pCaption->Create(szLabel, WS_CHILD|SS_CENTER|WS_VISIBLE,rect,pParent); } TTabItem::TTabItem(const TTabItem& obj) { *this = obj; } TTabItem& TTabItem::operator=(const TTabItem& obj) { m_pWnd = obj.m_pWnd; m_pCaption = obj.m_pCaption; m_bWndEnabled = obj.m_bWndEnabled; m_bEnabled = obj.m_bEnabled; m_bVisible = obj.m_bVisible; m_nMinX = obj.m_nMinX; m_nMaxX = obj.m_nMaxX; return *this; } TTabItem::~TTabItem() { // This is done in TVisualFramework::Destroy() //if (m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) // delete m_pWnd; ASSERT(m_pCaption); delete m_pCaption; } // Set rectangle for tab caption void TTabItem::SetRect(CRect& rect) { ASSERT(m_pCaption); m_pCaption->MoveWindow(&rect); } // Set font for tab caption void TTabItem::SetFont(CFont *pFont) { ASSERT(m_pCaption); ASSERT(pFont); m_pCaption->SetFont(pFont,FALSE); } // Get tab caption text CString TTabItem::GetText(void) { ASSERT(m_pCaption); CString str; m_pCaption->GetWindowText(str); return str; } int TTabItem::GetLength(void) { return m_nMaxX - m_nMinX; } // Set tab caption text void TTabItem::SetText(LPCTSTR szLabel) { ASSERT(m_pCaption); ASSERT(szLabel); m_pCaption->SetWindowText(szLabel); } // Enable/disable a window void TTabItem::Enable(BOOL bEnable) { m_bWndEnabled = bEnable; } // Enable/disable tab caption void TTabItem::EnableTab(BOOL bEnable) { ASSERT(m_pCaption); m_bEnabled = bEnable; m_pCaption->EnableWindow(m_bEnabled); } // Show/hide tab caption void TTabItem::ShowTab(BOOL bShow) { ASSERT(m_pCaption); m_bVisible = bShow; m_pCaption->ShowWindow(bShow ? SW_SHOW : SW_HIDE); } CWnd *TTabItem::GetSafeWnd(void) { return (m_pWnd && ::IsWindow(m_pWnd->m_hWnd)) ? m_pWnd : NULL; } //============================================================================= // class TTabWnd // //============================================================================= #define TABWND_DEFAULT_ID 0x2578 #define TABWND_HEIGHT 30 // Height of the gray border between the toolbar // and the client area #define TAB_HEIGHT 20 // Height on the normal tab #define TABSEL_HEIGHT 20 // Height of the selected tab #define TAB_SPACE 6 // Add to tab caption text width #define TAB_DEPL 4 // Distance between the tabs and the client area #define TAB_MAXLEN 200 IMPLEMENT_DYNCREATE(TTabWnd,CWnd) BEGIN_MESSAGE_MAP(TTabWnd, CWnd) //{{AFX_MSG_MAP(TTabWnd) ON_MESSAGE(WM_SIZEPARENT, OnSizeParent) ON_WM_ERASEBKGND() ON_WM_PAINT() ON_WM_LBUTTONUP() ON_WM_DESTROY() ON_WM_SIZE() ON_WM_CREATE() //}}AFX_MSG_MAP END_MESSAGE_MAP() TTabWnd::TTabWnd() { m_nSelectedTab = 0; m_bLockFlag = FALSE; m_nTabPos = TP_BOTTOM; // cache most used resources m_BrushBlack.CreateSolidBrush(RGB(0,0,0)); m_BrushLGray.CreateSolidBrush(::GetSysColor(COLOR_BTNFACE)); m_PenBlack.CreatePen(PS_SOLID, 1, (COLORREF)0); m_PenLGray.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNFACE)); m_PenWhite.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNHIGHLIGHT)); m_PenWhite2.CreatePen(PS_SOLID, 2, ::GetSysColor(COLOR_BTNHIGHLIGHT)); m_PenDGray.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_BTNSHADOW)); m_PenDGray2.CreatePen(PS_SOLID, 2, ::GetSysColor(COLOR_BTNSHADOW)); } TTabWnd::~TTabWnd() { } // Find a tab within this tab window TTabItem *TTabWnd::findTabItem(int nIndex) { int nNdx = 0; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { if (nNdx == nIndex) return (*iterator); nNdx ++; } return NULL; } // Create a tab window BOOL TTabWnd::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& prect, CWnd* pParentWnd, UINT nID, CCreateContext *pContext) { ASSERT(pParentWnd); dwStyle &= ~WS_BORDER; CRect rect(prect); if (!CWnd::Create(NULL, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext)) return FALSE; if (pParentWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { ((CFrameWnd*)pParentWnd)->ModifyStyleEx(WS_EX_CLIENTEDGE,0,SWP_FRAMECHANGED); ((CFrameWnd*)pParentWnd)->RecalcLayout(); } ResizeTab(); return TRUE; } int TTabWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; createFont(); return 0; } void TTabWnd::OnDestroy() { CWnd::OnDestroy(); TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator ++) { delete (*iterator); } m_TabList.clear(); // This is done in TVisualFramework //if (GetParent()->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) // delete this; } // Virtual function to check whether switch to new tab can be done BOOL TTabWnd::CanSetActivePane(CWnd *pOldPane, CWnd *pNewPane) { return TRUE; } // Virtual function (after the switch is done) void TTabWnd::OnSetActivePane(CWnd *pOldPane, CWnd *pNewPane) { } // Create fonts for tab labels void TTabWnd::createFont() { NONCLIENTMETRICS metrics; metrics.cbSize = sizeof(metrics); ::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0); CWindowDC wdc(NULL); int nLPixY = GetDeviceCaps(wdc.m_hDC, LOGPIXELSY); m_Font.CreateFontIndirect(&metrics.lfStatusFont); } // Add a tab to this window TTabItem *TTabWnd::addTab(CWnd *pWnd, LPCTSTR szLabel) { ASSERT(pWnd); ASSERT(szLabel); TTabItem *pItem = new TTabItem(this,szLabel); pItem->m_pWnd = pWnd; m_TabList.insert(m_TabList.end(), pItem); return pItem; } int TTabWnd::GetTabLength() { int nLength = 0; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { nLength += (*iterator)->GetLength(); } return nLength; } // Get index of currently selected tab int TTabWnd::GetTabIndex(void) { return m_nSelectedTab; } // Get number of tabs int TTabWnd::GetTabCount(void) { return m_TabList.size(); } // Get index of the tab associated with specified window int TTabWnd::GetTabIndex(CWnd *pWnd) { ASSERT(pWnd); int nIndex = 0; TTabItem *pItem; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { pItem = *iterator; if (pItem->m_pWnd == pWnd) return nIndex; nIndex ++; } return -1; } // Get pointer to window associated with the specified tab index CWnd *TTabWnd::GetTabWnd(int index) { TTabItem *pItem = findTabItem(index); ASSERT(pItem); return ::IsWindow(pItem->m_pWnd->m_hWnd) ? pItem->m_pWnd : NULL; } // Get tab caption text of the specified tab CString TTabWnd::GetTabLabel(int nIndex) { TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); return pItem->GetText(); } // Set text of tab caption void TTabWnd::SetTabLabel(int nIndex, LPCTSTR szLabel) { ASSERT(szLabel); TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); pItem->SetText(szLabel); invalidateTabArea(); } // Enable/disable a view void TTabWnd::Enable(int nIndex, BOOL bEnable) { TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); pItem->Enable(bEnable); //pItem->m_pWnd->EnableWindow(bEnable); } // Cannot disable currently selected tab void TTabWnd::EnableTab(int nIndex, BOOL bEnable) { ASSERT(nIndex != m_nSelectedTab); TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); pItem->EnableTab(bEnable); invalidateTabArea(); } // Cannot make invisible currently selected tab void TTabWnd::ShowTab(int nIndex, BOOL bShow) { ASSERT(nIndex != m_nSelectedTab); TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); pItem->ShowTab(bShow); invalidateTabArea(); } // Is tab enabled BOOL TTabWnd::IsTabEnabled(int nIndex) { TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); return pItem->m_bEnabled; } // Is tab visible BOOL TTabWnd::IsTabVisible(int nIndex) { TTabItem *pItem = findTabItem(nIndex); ASSERT(pItem); return pItem->m_bVisible; } // Set font void TTabWnd::SetFont(CFont *pFont) { ASSERT(pFont); CWnd::SetFont(pFont); m_Font.DeleteObject(); LOGFONT lf; pFont->GetLogFont(&lf); m_Font.CreateFontIndirect(&lf); invalidateTabArea(); } // Set position of tabs (top or bottom) void TTabWnd::SetTabPos(TTabPos nTabPos) { m_nTabPos = nTabPos; } // Invalidate rectangle to redraw tabs void TTabWnd::invalidateTabArea(void) { CRect rect; switch (m_nTabPos) { case TP_TOP: InvalidateRect(&CRect(0, 0, 32000, TABWND_HEIGHT)); break; case TP_BOTTOM: GetClientRect(&rect); InvalidateRect(&CRect(CPoint(0,rect.Height()-TABWND_HEIGHT), CSize(32000,TABWND_HEIGHT))); break; }; } // Draws a selected tab and returns its height int TTabWnd::drawSelTabTop(CDC *pDC, int x, CRect& client, TTabItem *pItem) { ASSERT(pItem); ASSERT(pDC); CString str = pItem->GetText(); CSize textSize = pDC->GetTextExtent(str); textSize.cx += 10; if (textSize.cx > TAB_MAXLEN) textSize.cx = TAB_MAXLEN; int y = TABWND_HEIGHT - TABSEL_HEIGHT - TAB_DEPL; // black border, no bottom line pDC->SelectObject(&m_PenBlack); pDC->MoveTo(x,y+TABSEL_HEIGHT-1); pDC->LineTo(x,y); pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y); pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y+TABSEL_HEIGHT); // left and upper border in white, double line pDC->SelectObject(&m_PenWhite2); pDC->MoveTo(x+2,y+TABSEL_HEIGHT-1); pDC->LineTo(x+2,y+2); pDC->LineTo(x+textSize.cx+TAB_SPACE-4, y+2); // right border, dark gray, double line pDC->SelectObject(&m_PenDGray2); pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y+2); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TABSEL_HEIGHT-1); // clean up pDC->SelectObject(&m_PenLGray); pDC->MoveTo(x-1, y+TABSEL_HEIGHT); pDC->LineTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT); pDC->MoveTo(x-1, y+TABSEL_HEIGHT+1); pDC->LineTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT+1); // a black line to far left and right pDC->SelectObject(&m_PenBlack); pDC->MoveTo(0, y+TABSEL_HEIGHT-1); pDC->LineTo(x, y+TABSEL_HEIGHT-1); pDC->MoveTo(x+textSize.cx+TAB_SPACE+1, y+TABSEL_HEIGHT-1); pDC->LineTo(client.right, y+TABSEL_HEIGHT-1); // and a white double line pDC->SelectObject(&m_PenWhite2); if (x!=0) { pDC->MoveTo(0, y+TABSEL_HEIGHT+1); pDC->LineTo(x, y+TABSEL_HEIGHT+1); } pDC->MoveTo(x+textSize.cx+TAB_SPACE, y+TABSEL_HEIGHT+1); pDC->LineTo(client.right, y+TABSEL_HEIGHT+1); // gray inside pDC->FillSolidRect(x+3, y+3,textSize.cx+TAB_SPACE-6, TABSEL_HEIGHT, ::GetSysColor(COLOR_BTNFACE)); CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2+1), textSize); pItem->SetFont(&m_Font); pItem->SetRect(rect); return textSize.cx+TAB_SPACE; } // Draw a selected tab at the bottom int TTabWnd::drawSelTabBottom(CDC *pDC, int x, CRect& client, TTabItem *pItem) { ASSERT(pItem); ASSERT(pDC); CString str = pItem->GetText(); CSize textSize = pDC->GetTextExtent(str); textSize.cx += 10; if (textSize.cx > TAB_MAXLEN) textSize.cx = TAB_MAXLEN; int y = client.Height() - TABWND_HEIGHT + TAB_DEPL; // black border, no bottom line pDC->SelectObject(&m_PenBlack); pDC->MoveTo(x,y); pDC->LineTo(x,y+TABSEL_HEIGHT); pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y+TABSEL_HEIGHT); pDC->LineTo(x+textSize.cx+TAB_SPACE-1, y); // left border in white, double line pDC->SelectObject(&m_PenWhite2); pDC->MoveTo(x+2,y); pDC->LineTo(x+2,y+TABSEL_HEIGHT-1); // right and bottom border, dark gray, double line pDC->SelectObject(&m_PenDGray2); pDC->LineTo(x+textSize.cx+TAB_SPACE-4, y+TABSEL_HEIGHT-1); pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TABSEL_HEIGHT-1); // a black line to far left and right pDC->SelectObject(&m_PenBlack); pDC->MoveTo(0, y); pDC->LineTo(x, y); pDC->MoveTo(x+textSize.cx+TAB_SPACE, y); pDC->LineTo(client.right, y); // and a gray line to far left and right pDC->SelectObject(&m_PenDGray); if (x != 0) { pDC->MoveTo(0, y-1); pDC->LineTo(x, y-1); } pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y-1); pDC->LineTo(client.right, y-1); // gray inside pDC->FillSolidRect(x+3,y,textSize.cx+TAB_SPACE-6, TABSEL_HEIGHT-2, ::GetSysColor(COLOR_BTNFACE)); CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2), textSize); pItem->SetFont(&m_Font); pItem->SetRect(rect); return textSize.cx+TAB_SPACE; } // Draws an unselected tab and returs its height int TTabWnd::drawTabTop(CDC *pDC, int x, CRect& client, TTabItem *pItem) { ASSERT(pItem); ASSERT(pDC); CString str = pItem->GetText(); CSize textSize = pDC->GetTextExtent(str); textSize.cx += 10; if (textSize.cx > TAB_MAXLEN) textSize.cx = TAB_MAXLEN; int y = TABWND_HEIGHT-TAB_HEIGHT-TAB_DEPL; // black border pDC->FrameRect(&CRect(CPoint(x,y), CSize(textSize.cx+TAB_SPACE, TAB_HEIGHT)), &m_BrushBlack); pDC->SelectObject(&m_PenWhite); pDC->MoveTo(x+1, y+1); pDC->LineTo(x+1, y+TAB_HEIGHT-1); pDC->MoveTo(x+1, y+1); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+1); pDC->SelectObject(&m_PenDGray); pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y+1); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); pDC->FillRect(&CRect(CPoint(x+2,y+2), CSize(textSize.cx+TAB_SPACE-4, TAB_HEIGHT-3)), &m_BrushLGray); // clean up int dy = TABSEL_HEIGHT-TAB_HEIGHT; pDC->FillSolidRect(x, y-dy, textSize.cx+TAB_SPACE, dy, GetSysColor(COLOR_BTNFACE)); CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2+1), textSize); pItem->SetFont(&m_Font); pItem->SetRect(rect); return textSize.cx+TAB_SPACE; } // Draw an unselected tab at the bottom int TTabWnd::drawTabBottom(CDC *pDC, int x, CRect& client, TTabItem *pItem) { ASSERT(pItem); ASSERT(pDC); CString str = pItem->GetText(); CSize textSize = pDC->GetTextExtent(str); textSize.cx += 10; if (textSize.cx > TAB_MAXLEN) textSize.cx = TAB_MAXLEN; int y = client.Height() - TABWND_HEIGHT + TAB_DEPL; // black border pDC->FrameRect(&CRect(CPoint(x,y), CSize(textSize.cx+TAB_SPACE, TAB_HEIGHT+1)), &m_BrushBlack); // Gray border bottom and right side pDC->SelectObject(&m_PenDGray); pDC->MoveTo(x+1, y+TAB_HEIGHT-1); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); pDC->MoveTo(x+textSize.cx+TAB_SPACE-2, y); pDC->LineTo(x+textSize.cx+TAB_SPACE-2, y+TAB_HEIGHT-1); pDC->FillRect(&CRect(CPoint(x+1,y+1), CSize(textSize.cx+TAB_SPACE-4, TAB_HEIGHT-3)), &m_BrushLGray); CRect rect(CPoint(x+TAB_SPACE/2, y+(TAB_HEIGHT-textSize.cy)/2), textSize); pItem->SetFont(&m_Font); pItem->SetRect(rect); return textSize.cx+TAB_SPACE; } // Draw edge arround client area void TTabWnd::drawClient(CDC *pDc, CRect& rect) { ASSERT(pDc); CWnd *pParent = GetParent(); ASSERT(pParent); switch (m_nTabPos) { case TP_TOP: if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { pDc->DrawEdge(&rect, EDGE_ETCHED, BF_TOP); } pDc->Draw3dRect(0,TABWND_HEIGHT, rect.right, rect.bottom-TABWND_HEIGHT, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); pDc->Draw3dRect(1,TABWND_HEIGHT+1, rect.right-2, rect.bottom-TABWND_HEIGHT-2, 0, ::GetSysColor(COLOR_3DLIGHT)); break; case TP_BOTTOM: if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { pDc->DrawEdge(&rect, EDGE_ETCHED, BF_BOTTOM); } pDc->Draw3dRect(0,0, rect.right, rect.bottom-TABWND_HEIGHT+1, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); pDc->Draw3dRect(1,1, rect.right-2, rect.bottom-TABWND_HEIGHT-1, 0, ::GetSysColor(COLOR_3DLIGHT)); break; } } void TTabWnd::OnPaint() { CPaintDC dc(this); // device context for painting CRect client; GetClientRect(&client); drawClient(&dc, client); int x = 0, nIndex = 0; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { TTabItem *pItem = *iterator; ASSERT(pItem != NULL); if (pItem->m_bVisible) { pItem->m_nMinX = x; if (nIndex != m_nSelectedTab) { switch (m_nTabPos) { case TP_TOP: x += drawTabTop(&dc, x, client, pItem); break; case TP_BOTTOM: x += drawTabBottom(&dc, x, client, pItem); break; } } else { switch (m_nTabPos) { case TP_TOP: x += drawSelTabTop(&dc, x, client, pItem); break; case TP_BOTTOM: x += drawSelTabBottom(&dc, x, client, pItem); break; } } } pItem->m_nMaxX = x; nIndex ++; } } // Returns tab index that holds specified point int TTabWnd::HitTest(CPoint& point) { return HitTest(point.x,point.y); } // Returns tab index that holds specified point int TTabWnd::HitTest(int x, int y) { int notsel_y_min, sel_y_min, y_max; CRect rect; GetClientRect(&rect); switch (m_nTabPos) { case TP_TOP: notsel_y_min = TABWND_HEIGHT - TAB_HEIGHT - TAB_DEPL; sel_y_min = TABWND_HEIGHT - TABSEL_HEIGHT - TAB_DEPL; y_max = TABWND_HEIGHT - TAB_DEPL; break; case TP_BOTTOM: notsel_y_min = rect.Height() - TABWND_HEIGHT + TAB_DEPL; sel_y_min = rect.Height() - TABWND_HEIGHT + TAB_DEPL; y_max = rect.Height() - TABWND_HEIGHT + TAB_DEPL + TAB_HEIGHT; break; }; int nIndex = 0; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { TTabItem *pItem = (*iterator); if (pItem->m_bEnabled && pItem->m_bVisible) { if (nIndex != m_nSelectedTab && (y < notsel_y_min || y > y_max)) continue; if (nIndex == m_nSelectedTab && (y < sel_y_min || y > y_max)) continue; if (x >= pItem->m_nMinX && x <= pItem->m_nMaxX) return nIndex; } nIndex++; } return -1; } // Switch focus to specified tab index BOOL TTabWnd::SetActivePane(int nIndex, BOOL bActivate) { if (nIndex == -1) return FALSE; if (nIndex == m_nSelectedTab) return TRUE; TTabItem *pNewPane = findTabItem(nIndex); if (!pNewPane->m_bEnabled || !pNewPane->m_bVisible) return FALSE; TTabItem *pOldPane = NULL; if (m_nSelectedTab != -1) pOldPane = findTabItem(m_nSelectedTab); if (CanSetActivePane(pOldPane ? pOldPane->m_pWnd : NULL, pNewPane->m_pWnd)) { // Deactivate old pane if (m_nSelectedTab != -1) { pOldPane->m_pWnd->EnableWindow(FALSE); pOldPane->m_pWnd->ShowWindow(SW_HIDE); } // Activate new pane pNewPane->m_pWnd->EnableWindow(pNewPane->m_bWndEnabled ? TRUE : FALSE); pNewPane->m_pWnd->ShowWindow(SW_SHOW); pNewPane->m_pWnd->SetFocus(); // Save index of new pane m_nSelectedTab = nIndex; // Invalidate tab invalidateTabArea(); // Inform derived class OnSetActivePane(pOldPane ? pOldPane->m_pWnd : NULL, pNewPane->m_pWnd); // Update frame window if (bActivate) { CWnd *pParent = GetParent(); while (pParent && !pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) pParent = pParent->GetParent(); ASSERT(pParent != NULL); updateFrame((CFrameWnd*)pParent, pNewPane->m_pWnd); } return TRUE; } return FALSE; } // Update frame window active view based on newly selected tab item BOOL TTabWnd::updateFrame(CFrameWnd *pFrame, CWnd *pWnd) { ASSERT(pFrame); ASSERT(pWnd); if (pWnd->IsKindOf(RUNTIME_CLASS(CView))) { // New tab item is a view pFrame->SetActiveView((CView*)pWnd); return TRUE; } else if (pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; CWnd *pView = pSplitter->GetActivePane(); if (pView == NULL) { CWnd *pTmpView; for (int x = 0; x < pSplitter->GetRowCount(); x ++) { for (int y = 0; y < pSplitter->GetColumnCount(); y ++) { pTmpView = pSplitter->GetPane(x,y); if (pTmpView->IsWindowEnabled()) { if (updateFrame(pFrame, pTmpView)) return TRUE; } } } } if (pView == NULL) pView = pSplitter->GetPane(0,0); pFrame->SetActiveView((CView*)pView); } else if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pWnd; int nIndex = pTab->GetTabIndex(); CWnd *pTabWnd = pTab->GetTabWnd(nIndex); if (updateFrame(pFrame, pTabWnd)) return TRUE; } return FALSE; } // Resize tab void TTabWnd::ResizeTab(int cx, int cy) { CRect rect; CWnd *pParent = (CWnd*)GetParent(); ASSERT(pParent); pParent->GetClientRect(&rect); if (pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { CSplitterWnd *splitter = (CSplitterWnd*)pParent; ASSERT(pParent); int row,col; splitter->IsChildPane(this,row,col); splitter->RecalcLayout(); } else if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { m_bLockFlag = TRUE; pParent->RepositionBars(0, 0xFFFF, AFX_IDW_PANE_FIRST, CWnd::reposQuery, &rect); MoveWindow(rect.left,rect.top,rect.Width(),rect.Height()); m_bLockFlag = FALSE; } m_bLockFlag = TRUE; // reentrancy check (might get called recursivly from OnSize) CWnd *pWnd; TTabItemList::iterator iterator; for (iterator = m_TabList.begin(); iterator != m_TabList.end(); iterator++) { pWnd = (*iterator)->m_pWnd; if (cx == -1 && cy == -1) { switch (m_nTabPos) { case TP_TOP: pWnd->MoveWindow(1, TABWND_HEIGHT+1, rect.Width()-2, rect.Height()-TABWND_HEIGHT-2); break; case TP_BOTTOM: pWnd->MoveWindow(1, 0, rect.Width()-2, rect.Height()-TABWND_HEIGHT); break; } } else { switch (m_nTabPos) { case TP_TOP: pWnd->MoveWindow(1, TABWND_HEIGHT+1, cx, cy-TABWND_HEIGHT-2); break; case TP_BOTTOM: pWnd->MoveWindow(1, 0, cx, cy-TABWND_HEIGHT); break; } } } m_bLockFlag=FALSE; } // Erase area where the tabs are displayed BOOL TTabWnd::OnEraseBkgnd(CDC* pDC) { ASSERT(pDC); CRect rect; GetClientRect(&rect); switch (m_nTabPos) { case TP_TOP: pDC->FillSolidRect(&CRect(0, 0, rect.right, TABWND_HEIGHT), ::GetSysColor(COLOR_BTNFACE)); break; case TP_BOTTOM: pDC->FillSolidRect(&CRect(0, rect.bottom-TABWND_HEIGHT-3, rect.right, rect.bottom), ::GetSysColor(COLOR_BTNFACE)); break; } return TRUE; } // Handle couse click on tabs void TTabWnd::OnLButtonUp(UINT nFlags, CPoint point) { int nNewTab = HitTest(point.x, point.y); SetActivePane(nNewTab); CWnd::OnLButtonUp(nFlags, point); } // Handle resize LRESULT TTabWnd::OnSizeParent(WPARAM, LPARAM lParam) { if (m_bLockFlag) return 0; ResizeTab(); return 0; } // Handle resize void TTabWnd::OnSize(UINT nType, int cx, int cy) { CWnd::OnSize(nType, cx, cy); ResizeTab(cx,cy); } // Create a CView derived class as a tab TTabItem *TTabWnd::CreatePane(LPCTSTR lpszLabel, CRuntimeClass *pViewClass, CCreateContext *pContext) { CRect rect, client; ASSERT(pViewClass && pContext); CWnd *pWnd = (CWnd*)pViewClass->CreateObject(); if (!pWnd) return NULL; GetClientRect(&client); rect.left = 0; rect.top = TABWND_HEIGHT+2; rect.right = client.right; rect.bottom = client.bottom; int dwStyle = AFX_WS_DEFAULT_VIEW; if (GetParent()->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { dwStyle &= ~WS_BORDER; } if (!pWnd->Create(NULL, NULL, dwStyle, rect, this, 13576+m_TabList.size(), pContext)) { TRACE0("Warning: couldn't create client area for tab view\n"); // pWnd will be cleaned up by PostNcDestroy return NULL; } // Insert new tab object into the list TTabItem *pTab = addTab(pWnd,lpszLabel); ASSERT(pTab); if (m_TabList.size() != 1) { pWnd->EnableWindow(FALSE); pWnd->ShowWindow(SW_HIDE); /* // Framework is responsible to set the active view } else { CWnd *pParent = GetParent(); if (pParent->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { ((CFrameWnd*)pParent)->SetActiveView((CView*)pWnd); } else if (pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { ((CSplitterWnd*)pParent)->SetActivePane(0,0,pWnd); } */ } return pTab; } // Create a splitter window as a tab TTabItem *TTabWnd::CreatePane(LPCTSTR lpszLabel, int nRows, int nCols, CWnd *pWnd, UINT nID) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); // Moved to TVisualFramework to handle creation of CSplitterWnd derived classes //CSplitterWnd *pWnd = new CSplitterWnd; //if (!pWnd) // return NULL; int dwStyle = AFX_WS_DEFAULT_VIEW; dwStyle &= ~WS_BORDER; CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; if (!pSplitter->CreateStatic(this, nRows, nCols, dwStyle, nID)) { TRACE0("Warning: couldn't create client area for tab view\n"); // pWnd will be cleaned up by PostNcDestroy return NULL; } TTabItem *pTab = addTab(pWnd,lpszLabel); ASSERT(pTab); if (m_TabList.size() != 1) { pWnd->EnableWindow(FALSE); pWnd->ShowWindow(SW_HIDE); } /* // Framework will set the active view CWnd *paneWnd = pWnd->GetActivePane(); if (paneWnd) { ((CFrameWnd*)GetParent())->SetActiveView((CView*)paneWnd); } else { paneWnd = pWnd->GetPane(0,0); pWnd->SetActivePane(0,0); ((CFrameWnd*)GetParent())->SetActiveView((CView*)paneWnd); } */ return pTab; } //============================================================================= // class TVisualObject // //============================================================================= // Private constructor TVisualObject::TVisualObject() { } // Create a plain view TVisualObject::TVisualObject(DWORD dwId, CCreateContext *pContext, CRuntimeClass *pClass) { ASSERT(pContext); ASSERT(pClass); ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CView))); zeroAll(); m_dwId = dwId; m_nObjectType = OT_VIEW; m_pContext = pContext; m_pRuntimeClass = pClass; checkStyle(); } // Create a view within a tab window or a tab window TVisualObject::TVisualObject(DWORD dwId, LPCTSTR szTitle, CCreateContext *pContext, CRuntimeClass *pClass, DWORD dwStyle) { ASSERT(szTitle); ASSERT(pContext); ASSERT(pClass); zeroAll(); m_dwId = dwId; if (pClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))) { m_nObjectType = OT_TAB; } else if (pClass->IsDerivedFrom(RUNTIME_CLASS(CView))) { m_nObjectType = OT_TABVIEW; } else { ASSERT(FALSE); } m_strTitle = szTitle; m_pContext = pContext; m_pRuntimeClass = pClass; m_dwStyle = dwStyle; checkStyle(); } // Create a splitter window TVisualObject::TVisualObject(DWORD dwId, LPCTSTR szTitle, int nRows, int nCols, CCreateContext *pContext, DWORD dwStyle) { ASSERT(szTitle); ASSERT(pContext); ASSERT(nRows); ASSERT(nCols); zeroAll(); m_dwId = dwId; m_nObjectType = OT_SPLITTER; m_strTitle = szTitle; m_pContext = pContext; m_nRows = nRows; m_nCols = nCols; m_dwStyle = dwStyle; checkStyle(); } // Create a view within a splitter window TVisualObject::TVisualObject(DWORD dwId, int nRow, int nCol, CCreateContext *pContext, CRuntimeClass *pClass, CSize size, DWORD dwStyle) { ASSERT(pContext); ASSERT(pClass); ASSERT(pClass->IsDerivedFrom(RUNTIME_CLASS(CView)) || pClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); zeroAll(); m_dwId = dwId; m_nObjectType = OT_SPLITTERVIEW; m_pContext = pContext; m_pRuntimeClass = pClass; m_nRowIndex = nRow; m_nColIndex = nCol; m_Size = size; m_dwStyle = dwStyle; checkStyle(); } // Create a splitter within a splitter window TVisualObject::TVisualObject(DWORD dwId, int nRow, int nCol, int nRows, int nCols, CCreateContext *pContext, DWORD dwStyle) { ASSERT(pContext); ASSERT(nRows); ASSERT(nCols); zeroAll(); m_dwId = dwId; m_nObjectType = OT_SPLITTERSPLITTER; m_pContext = pContext; m_nRowIndex = nRow; m_nColIndex = nCol; m_nRows = nRows; m_nCols = nCols; m_dwStyle = dwStyle; checkStyle(); } TVisualObject::TVisualObject(const TVisualObject& obj) { zeroAll(); *this = obj; } TVisualObject::~TVisualObject() { } TVisualObject& TVisualObject::operator=(const TVisualObject& obj) { // No need to copy m_ObjectList since it is populated after // this code is executed in STL container m_nObjectType = obj.m_nObjectType; m_dwId = obj.m_dwId; m_pWnd = obj.m_pWnd; m_pParent = obj.m_pParent; m_strTitle = obj.m_strTitle; m_nRows = obj.m_nRows; m_nCols = obj.m_nCols; m_nRowIndex = obj.m_nRowIndex; m_nColIndex = obj.m_nColIndex; m_pContext = obj.m_pContext; m_pRuntimeClass = obj.m_pRuntimeClass; m_Size = obj.m_Size; m_bEnabled = obj.m_bEnabled; m_dwStyle = obj.m_dwStyle; m_cHotKey = obj.m_cHotKey; m_pOwner = obj.m_pOwner; m_pFramework = obj.m_pFramework; return *this; } void TVisualObject::zeroAll(void) { // No need to zero m_ObjectList since it is already empty m_nObjectType = OT_UNKNOWN; m_dwId = 0; m_pWnd = NULL; m_pParent = NULL; m_strTitle = _T(""); m_nRows = 0; m_nCols = 0; m_nRowIndex = 0; m_nColIndex = 0; m_pContext = NULL; m_pRuntimeClass = NULL; m_Size = CSize(0,0); m_bEnabled = TRUE; m_dwStyle = 0; m_cHotKey = 0; m_pOwner = NULL; m_pFramework = NULL; } // Check if style is valid void TVisualObject::checkStyle(void) { if ((m_dwStyle & TOS_TABTOP) || (m_dwStyle & TOS_TABBOTTOM)) { ASSERT(m_pRuntimeClass); // Tab position valid only for tab window derived classes ASSERT(m_pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); } if (m_dwStyle & TOS_SELECTED) { // Selected valid only for tab panes that are not splitters and tabs // In this case, use TVisualFramework::SetActivePane() to set the active pane // once the framework is created if (m_pRuntimeClass == NULL) { // Splitters canot be dynamically create (m_pRuntimeClass is NULL) ASSERT((m_nObjectType != OT_SPLITTER) && (m_nObjectType != OT_SPLITTERVIEW)); } else { ASSERT(!m_pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(TTabWnd))); } } } // Delete the window pointer and optionally destroy the window void TVisualObject::Destroy(BOOL bDestroyWindow) { if (m_pWnd) { if (bDestroyWindow) m_pWnd->DestroyWindow(); delete m_pWnd; m_pWnd = NULL; } } // If this object is a tab window or splitter window that it // cannot be focused BOOL TVisualObject::CanFocus(void) { ASSERT(m_pWnd); if (m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd)) || m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { return FALSE; } return TRUE; } // Set hot key for this tab object void TVisualObject::SetHotKey(CHAR cHotKey) { m_cHotKey = cHotKey; } // Optional: Set description void TVisualObject::SetDescription(LPCTSTR szDesc) { m_strDescription = szDesc; } // Set this object as active pane BOOL TVisualObject::SetActivePane(void) { ASSERT(m_pFramework); return m_pFramework->SetActivePane(this); } // Set this tab to be active tab (not the active pane) BOOL TVisualObject::SetActiveTab(void) { ASSERT(m_pFramework); return m_pFramework->SetActiveTab(this); } // Enable/disable this object BOOL TVisualObject::Enable(BOOL bEnable) { ASSERT(m_pFramework); return m_pFramework->Enable(this,bEnable); } // Enable/disable tab BOOL TVisualObject::EnableTab(BOOL bEnable) { ASSERT(m_pFramework); return m_pFramework->EnableTab(this,bEnable); } // SHow/hide this object BOOL TVisualObject::ShowTab(BOOL bShow) { ASSERT(m_pFramework); return m_pFramework->ShowTab(this,bShow); } // Is this object enabled BOOL TVisualObject::IsEnabled(BOOL& bEnabled) { ASSERT(m_pFramework); return m_pFramework->IsEnabled(this,bEnabled); } // Is this object enabled BOOL TVisualObject::IsTabEnabled(BOOL& bEnabled) { ASSERT(m_pFramework); return m_pFramework->IsTabEnabled(this,bEnabled); } // Is this object visible BOOL TVisualObject::IsTabVisible(BOOL& bVisible) { ASSERT(m_pFramework); return m_pFramework->IsTabVisible(this,bVisible); } // Returns TRUE if this object is a tab within a tab window BOOL TVisualObject::IsTabPane(void) { ASSERT(m_pFramework); return m_pFramework->IsTabPane(this); } // Returns TRUE if this object is a tab window BOOL TVisualObject::IsTabWindow(void) { ASSERT(m_pFramework); return m_pFramework->IsTabWindow(this); } // Returns TRUE if this object is a pane within a splitter window BOOL TVisualObject::IsSplitterPane(void) { ASSERT(m_pFramework); return m_pFramework->IsSplitterPane(this); } // Returns TRUE if this object is a splitter window BOOL TVisualObject::IsSplitterWindow(void) { ASSERT(m_pFramework); return m_pFramework->IsSplitterWindow(this); } // Returns TRUE if this object is derived from CView BOOL TVisualObject::IsView(void) { ASSERT(m_pFramework); return m_pFramework->IsView(this); } // Get object ID #ifdef _DEBUG DWORD TVisualObject::GetID(void) { return m_dwId; } #endif // Get object window #ifdef _DEBUG CWnd *TVisualObject::GetWnd(void) { return m_pWnd; } #endif // Get safe object window #ifdef _DEBUG CWnd *TVisualObject::GetSafeWnd(void) { return ::IsWindow(m_pWnd->m_hWnd) ? m_pWnd : NULL; } #endif #ifdef _DEBUG CString TVisualObject::GetTitle(void) { return m_strTitle; } #endif #ifdef _DEBUG CString TVisualObject::GetDescription(void) { return m_strDescription; } #endif #ifdef _DEBUG CWnd *TVisualObject::GetParentWnd(void) { return m_pParent; } #endif #ifdef _DEBUG TVisualFramework *TVisualObject::GetFramework(void) { return m_pFramework; } #endif #ifdef _DEBUG TVisualObject *TVisualObject::GetOwner(void) { return m_pOwner; } #endif //============================================================================= // class TVisualFramework // //============================================================================= IMPLEMENT_DYNCREATE(TVisualFramework, CCmdTarget) BEGIN_MESSAGE_MAP(TVisualFramework, CCmdTarget) //{{AFX_MSG_MAP(TVisualFramework) //}}AFX_MSG_MAP END_MESSAGE_MAP() TVisualFramework::TVisualFramework() { m_pOwner = NULL; m_bEnableCtrlTab = TRUE; } TVisualFramework::~TVisualFramework() { if (m_ObjectMap.size() && m_ObjectList.size()) { TRACE0(_T(">>> TVisualFramework::Destroy() called in TVisualFramework destructor\n")); TRACE0(_T(">>> It must be called in CFrameWnd derived class OnDestroy() message handler\n")); Destroy(); } } // Find an object in the map with the specified unique id TVisualObject *TVisualFramework::findObject(DWORD dwId) { TVisualObjectMap::iterator iterator; for (iterator = m_ObjectMap.begin(); iterator != m_ObjectMap.end(); iterator++) { if (dwId == iterator->first) return iterator->second; } return NULL; } // Find an object in the map with the specified window TVisualObject *TVisualFramework::findObject(CWnd *pWnd) { TVisualObjectMap::iterator iterator; for (iterator = m_ObjectMap.begin(); iterator != m_ObjectMap.end(); iterator++) { if (pWnd == iterator->second->m_pWnd) return iterator->second; } return NULL; } // Add object to the container (this is a root level object) // There is only one root level object (either splitter or tab) BOOL TVisualFramework::Add(TVisualObject *pObject) { ASSERT(pObject); ASSERT(m_ObjectList.size() == 0); // Only one root level object allowed // Root level object is either a view, splitter or a tab ASSERT((pObject->m_nObjectType == TVisualObject::OT_TAB) || (pObject->m_nObjectType == TVisualObject::OT_VIEW) || (pObject->m_nObjectType == TVisualObject::OT_SPLITTER)); if (findObject(pObject->m_dwId) == NULL) { m_ObjectList.insert(m_ObjectList.end(), pObject); pObject->m_pFramework = this; m_ObjectMap[pObject->m_dwId] = pObject; return TRUE; } ASSERT(FALSE); // Duplicate object Id return FALSE; } // Add child object to the specified object BOOL TVisualFramework::Add(TVisualObject *pOwner, TVisualObject *pObject) { ASSERT(pObject); #ifdef _DEBUG // Validate definition if (pOwner->m_nObjectType == TVisualObject::OT_TAB) { if ((pObject->m_nObjectType != TVisualObject::OT_TABVIEW) && (pObject->m_nObjectType != TVisualObject::OT_SPLITTER) && (pObject->m_nObjectType != TVisualObject::OT_TAB)) { ASSERT(FALSE); } } else if (pOwner->m_nObjectType == TVisualObject::OT_SPLITTER) { if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTERVIEW) && (pObject->m_nObjectType != TVisualObject::OT_SPLITTERSPLITTER)) { ASSERT(FALSE); } } else if (pOwner->m_nObjectType == TVisualObject::OT_SPLITTERSPLITTER) { if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTERVIEW) && (pObject->m_nObjectType != TVisualObject::OT_SPLITTERSPLITTER)) { ASSERT(FALSE); } } else if (pOwner->m_nObjectType == TVisualObject::OT_TABVIEW) { if ((pObject->m_nObjectType != TVisualObject::OT_SPLITTER)) { ASSERT(FALSE); } } #endif if (findObject(pObject->m_dwId) == NULL) { pOwner->m_ObjectList.insert(pOwner->m_ObjectList.end(), pObject); pObject->m_pOwner = pOwner; pObject->m_pFramework = this; m_ObjectMap[pObject->m_dwId] = pObject; return TRUE; } ASSERT(FALSE); // Duplicate object Id return FALSE; } // Create all objects within the framework BOOL TVisualFramework::Create(CWnd *pWnd) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))); // Save owner for later m_pOwner = pWnd; // Disable Ctrl+Tab for MDI applications if (pWnd->IsKindOf(RUNTIME_CLASS(CMDIChildWnd))) m_bEnableCtrlTab = FALSE; // Walk thru visual object hierarchy and create windows BOOL rc; TVisualObject *pObject; TVisualObjectList::iterator it; for (it = m_ObjectList.begin(); it != m_ObjectList.end(); it++) { pObject = *it; rc = execCreate(pWnd, pObject); if (rc == FALSE) { TRACE0(_T("Create visual object failed!\n")); return FALSE; } } // Walk thru the map and find first object that can be focused // Then set focus TVisualObjectMap::iterator mapit; for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { pObject = mapit->second; if (pObject->CanFocus()) { SetActivePane(pObject); break; } } return TRUE; } // Destroy all objects in the framework void TVisualFramework::Destroy(void) { TVisualObject *pObject; // Recursive delete of all objects TVisualObjectList::iterator it; for (it = m_ObjectList.begin(); it != m_ObjectList.end(); it++) { pObject = *it; execDestroy(pObject); } // Delete pointers in object map TVisualObjectMap::iterator mapit; for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit++) { pObject = mapit->second; delete pObject; } // Empty all containers (for check in destructor) m_ObjectMap.clear(); m_ObjectList.clear(); } // Recursive function to delete all object windows. Does not delete views since // they are destroyed by frame. void TVisualFramework::execDestroy(TVisualObject *pObject) { if (pObject->m_pWnd && ::IsWindow(pObject->m_pWnd->m_hWnd)) { if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TVisualObject *pObj; TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { pObj = *it; execDestroy(pObj); } pObject->Destroy(TRUE); } else if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) { TVisualObject *pObj; TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { pObj = *it; execDestroy(pObj); } pObject->Destroy(TRUE); } } } // Create specified object and all its childs BOOL TVisualFramework::execCreate(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pObject); BOOL rc = FALSE; switch (pObject->m_nObjectType) { case (TVisualObject::OT_SPLITTER): rc = execCreateSplitter(pWnd,pObject); break; case (TVisualObject::OT_SPLITTERVIEW): rc = execCreateSplitterView(pWnd, pObject); break; case (TVisualObject::OT_SPLITTERSPLITTER): rc = execCreateSplitterSplitter(pWnd, pObject); break; case (TVisualObject::OT_TAB): rc = execCreateTabWnd(pWnd, pObject); break; case (TVisualObject::OT_TABVIEW): rc = execCreateTabView(pWnd, pObject); break; case (TVisualObject::OT_VIEW): rc = execCreateView(pWnd, pObject); break; } return rc; } // Create a simple view BOOL TVisualFramework::execCreateView(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))); ASSERT(pObject); ASSERT(pObject->m_pContext); ASSERT(pObject->m_pRuntimeClass); CFrameWnd *pFrame = (CFrameWnd*)pWnd; pObject->m_pContext->m_pNewViewClass = pObject->m_pRuntimeClass; pObject->m_pWnd = pFrame->CreateView(pObject->m_pContext); ASSERT(pObject->m_pWnd); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pFrame; setTabWndProperties(pObject); return TRUE; } // Create a view within a tab window BOOL TVisualFramework::execCreateTabView(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))); ASSERT(pObject); ASSERT(pObject->m_pContext); ASSERT(pObject->m_pRuntimeClass); ASSERT(!pObject->m_strTitle.IsEmpty()); TTabWnd *pTab = (TTabWnd*)pWnd; TTabItem *pItem; pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_pRuntimeClass, pObject->m_pContext); ASSERT(pItem); pObject->m_pWnd = pItem->GetSafeWnd(); ASSERT(pObject->m_pWnd); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pTab; setTabWndProperties(pObject); return TRUE; } // Create a splitter window BOOL TVisualFramework::execCreateSplitter(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pObject); // Cannot use pObject->m_pRuntimeClass->CreateObject() since splitters // do not support dynamic creation pObject->m_pWnd = CreateSplitter(pObject->m_dwId); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pWnd; TTabItem *pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_nRows, pObject->m_nCols, pObject->m_pWnd); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pWnd; } else if (pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) { ((CSplitterWnd*)pObject->m_pWnd)->CreateStatic(pWnd,pObject->m_nRows,pObject->m_nCols); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pWnd; } setTabWndProperties(pObject); TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { execCreate(pObject->m_pWnd, *it); } return TRUE; } // Create a view within a splitter. Then create all childs of this view. BOOL TVisualFramework::execCreateSplitterView(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); ASSERT(pObject); CSplitterWnd *pSplitter = (CSplitterWnd*)pWnd; pSplitter->CreateView(pObject->m_nRowIndex, pObject->m_nColIndex, pObject->m_pRuntimeClass, pObject->m_Size, pObject->m_pContext); pObject->m_pWnd = pSplitter->GetPane(pObject->m_nRowIndex, pObject->m_nColIndex); ASSERT(pObject->m_pWnd); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pSplitter; setTabWndProperties(pObject); TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { execCreate(pObject->m_pWnd, *it); } return TRUE; } // Create a nested splitter window BOOL TVisualFramework::execCreateSplitterSplitter(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); CSplitterWnd *pParent = (CSplitterWnd*)pWnd; // Cannot use pObject->m_pRuntimeClass->CreateObject() since splitters // do not support dynamic creation pObject->m_pWnd = CreateSplitter(pObject->m_dwId); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))); CSplitterWnd *pSplitter = (CSplitterWnd*)pObject->m_pWnd; pSplitter->CreateStatic(pParent, pObject->m_nRows, pObject->m_nCols, WS_CHILD|WS_VISIBLE|WS_BORDER, pParent->IdFromRowCol(pObject->m_nRowIndex,pObject->m_nColIndex)); ASSERT(::IsWindow(pSplitter->m_hWnd)); pObject->m_pParent = pParent; TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { execCreate(pObject->m_pWnd, *it); } return TRUE; } // Create a tab window and all its childs (tabs) BOOL TVisualFramework::execCreateTabWnd(CWnd *pWnd, TVisualObject *pObject) { ASSERT(pWnd); ASSERT(pObject); if (pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pWnd; TTabItem *pItem = pTab->CreatePane(pObject->m_strTitle, pObject->m_pRuntimeClass, pObject->m_pContext); ASSERT(pItem); pObject->m_pWnd = pItem->GetSafeWnd(); ASSERT(pObject->m_pWnd); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); pObject->m_pParent = pWnd; setTabWndProperties(pObject); } else { CRect rect; pObject->m_pWnd = (CWnd*)pObject->m_pRuntimeClass->CreateObject(); ASSERT(pObject->m_pWnd); pObject->m_pParent = pWnd; pObject->m_pWnd->Create(NULL,_T(""),WS_VISIBLE|WS_CHILD, rect,pWnd,TABWND_DEFAULT_ID); ASSERT(::IsWindow(pObject->m_pWnd->m_hWnd)); setTabWndProperties(pObject); } TVisualObject *pObj; TVisualObjectList::iterator it; for (it = pObject->m_ObjectList.begin(); it != pObject->m_ObjectList.end(); it++) { pObj = *it; execCreate(pObject->m_pWnd, pObj); } return TRUE; } // Set properties of tab window void TVisualFramework::setTabWndProperties(TVisualObject *pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd != NULL); // If this is a tab window then set the position of tabs if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; if (pObject->m_dwStyle & TVisualObject::TOS_TABTOP) pTab->SetTabPos(TTabWnd::TP_TOP); else if (pObject->m_dwStyle & TVisualObject::TOS_TABBOTTOM) pTab->SetTabPos(TTabWnd::TP_BOTTOM); } // If this is a pane within a tab then check if this pane // should be a selected pane ASSERT(pObject->m_pParent); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; if (pObject->m_dwStyle & TVisualObject::TOS_SELECTED) { int nIndex = pTab->GetTabIndex(pObject->m_pWnd); pTab->SetActivePane(nIndex); } } } // Get owner pointer (CFrameWnd derived class) CWnd *TVisualFramework::GetWnd(void) { return m_pOwner; } // Get safe owner pointer (CFrameWnd derived class) CWnd *TVisualFramework::GetSafeWnd(void) { if (m_pOwner && ::IsWindow(m_pOwner->m_hWnd)) return m_pOwner; return NULL; } // Get window associated with the visual object specified with its id // Can be any object (view, splitter or tab window) CWnd *TVisualFramework::GetObject(DWORD dwId) { TVisualObject *pObject = findObject(dwId); if (pObject == NULL) return NULL; return pObject->m_pWnd; } // Get ID associated with the visual object specified with its window pointer // Can be any object (view, splitter or tab window) DWORD TVisualFramework::GetObject(CWnd *pWnd) { ASSERT(pWnd); TVisualObject *pObject = findObject(pWnd); if (pObject == NULL) return NULL; return pObject->m_dwId; } // Return a visual object with the specified id TVisualObject *TVisualFramework::Get(DWORD dwId) { return findObject(dwId); } // Return a visual object with the specified window TVisualObject *TVisualFramework::Get(CWnd *pWnd) { return findObject(pWnd); } // Returns an object that represents the currently active tab within the // supplied tab window object. This may not be the active pane TVisualObject *TVisualFramework::GetActiveTab(TVisualObject *pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); if (!pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) return NULL; TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; int nIndex = pTab->GetTabIndex(); CWnd *pWnd = pTab->GetTabWnd(nIndex); ASSERT(pWnd); return Get(pWnd); } // Set the active tab of the parent tab window. This will not activate the // pane associated with the active tab. BOOL TVisualFramework::SetActiveTab(TVisualObject *pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (!pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) return FALSE; TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); return pTab->SetActivePane(nIndex,FALSE); } // Returns TRUE if object is a tab within a tab window BOOL TVisualFramework::IsTabPane(TVisualObject* pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) return TRUE; return FALSE; } // Returns TRUE if object is a tab window BOOL TVisualFramework::IsTabWindow(TVisualObject* pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) return TRUE; return FALSE; } // Returns TRUE if object is a pane within a splitter window BOOL TVisualFramework::IsSplitterPane(TVisualObject* pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) return TRUE; return FALSE; } // Returns TRUE if object is a pane within a splitter window BOOL TVisualFramework::IsSplitterWindow(TVisualObject* pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) return TRUE; return FALSE; } // Returns TRUE if object is derived from CView BOOL TVisualFramework::IsView(TVisualObject *pObject) { ASSERT(pObject); ASSERT(pObject->m_pWnd); if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) return TRUE; return FALSE; } // Get the count of visual objects int TVisualFramework::GetCount(void) { return m_ObjectMap.size(); } // Set font for complete framework void TVisualFramework::SetFont(CFont *pFont) { ASSERT(pFont); TVisualObject *pObject; TVisualObjectMap::iterator mapit; for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { pObject = mapit->second; if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { ((TTabWnd*)pObject->m_pWnd)->SetFont(pFont); } else if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TVisualFormView))) { ((TVisualFormView*)pObject->m_pWnd)->SetFont(pFont); } else { pObject->m_pWnd->SetFont(pFont); } } } // Enable/disable CtrlTab for tab window void TVisualFramework::EnableCtrlTab(BOOL bEnable) { // If framework is used in an MDI application, then Ctrl+Tab is used to switch // among open windows. If it is enabled, Ctrl+Tab will then switch among // tab panes within the MDI child frame window (this disables default Ctrl+Tab // for MDI windows). // Ctrl+Tab works only if CWinApp derived class overloads PreTranslateMessage // and calles ProcessMessage() of the active TVisualFramework object m_bEnableCtrlTab = bEnable; } // Since CSplitterWnd does not support dynamic creation, this is a chance for // derived class to supply CSplitterWnd derived class instead of CSplitterWnd CSplitterWnd *TVisualFramework::CreateSplitter(DWORD dwId) { return new CSplitterWnd; } // Set focus to visual object BOOL TVisualFramework::SetActivePane(TVisualObject *pObject) { ASSERT(pObject); // Cannot set focus to splitter or tab window if (!pObject->CanFocus()) return FALSE; // Cannot set focus to disabled window BOOL bEnabled; if (pObject->IsEnabled(bEnabled) && !bEnabled) return FALSE; // Build a list that walks thru the object hierarchy from specified // object to the root TVisualObjectList list; TVisualObject *pObj = pObject; while (pObj) { list.insert(list.end(),pObj); pObj = pObj->m_pOwner; } // Reverse the list so that we can walk from root to the desired object list.reverse(); // Now, walk thru the list and set focus as desired TVisualObjectList::iterator it; for (it = list.begin(); it != list.end(); it ++) { pObj = *it; if (pObj->m_pOwner && pObj->m_pOwner->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObj->m_pOwner->m_pWnd; int nIndex = pTab->GetTabIndex(pObj->m_pWnd); if (!pTab->SetActivePane(nIndex)) return FALSE; } } // Update framework owner CFrameWnd *pFrame = (CFrameWnd*)m_pOwner; pFrame->SetActiveView((CView*)pObject->m_pWnd); return TRUE; } // Return a pointer to visual object that represents the currently active pane TVisualObject *TVisualFramework::GetActivePane(void) { CFrameWnd *pFrame = (CFrameWnd*)m_pOwner; ASSERT(pFrame); CView *pView = pFrame->GetActiveView(); ASSERT(pView); return findObject(pView); } // Enable/disable a view. Returns TRUE if sucessful BOOL TVisualFramework::Enable(TVisualObject *pObject, BOOL bEnable) { ASSERT(pObject); ASSERT(pObject->m_pWnd); if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) { pObject->m_bEnabled = bEnable; pObject->m_pWnd->EnableWindow(bEnable); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); pTab->Enable(nIndex, bEnable); } return TRUE; } return FALSE; } // Enable/disable a tab BOOL TVisualFramework::EnableTab(TVisualObject *pObject, BOOL bEnable) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); // Check if parent is a tab window if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); if (nIndex == pTab->GetTabIndex()) return FALSE; pTab->EnableTab(nIndex, bEnable); pObject->m_bEnabled = bEnable; return TRUE; } return FALSE; } // Show/hide a tab BOOL TVisualFramework::ShowTab(TVisualObject *pObject, BOOL bShow) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (!pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) return FALSE; TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); if (nIndex == pTab->GetTabIndex()) return FALSE; pTab->ShowTab(nIndex, bShow); return TRUE; } // Is object enabled. Returns FALSE if this is not a valid call for the supplied // object. If return code is TRUE, check bEnabled BOOL TVisualFramework::IsEnabled(TVisualObject *pObject, BOOL& bEnabled) { ASSERT(pObject); ASSERT(pObject->m_pWnd); bEnabled = pObject->m_bEnabled; return TRUE; /* if (pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(CView))) { bEnabled = pObject->m_pWnd->IsWindowEnabled(); return TRUE; } return FALSE; */ } // Is tab enabled. Returns FALSE if this is not a valid call for the supplied // object. If return code is TRUE, check bEnabled BOOL TVisualFramework::IsTabEnabled(TVisualObject *pObject, BOOL& bEnabled) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); bEnabled = pTab->IsTabEnabled(nIndex); return TRUE; } return FALSE; } // Is tab visible. Returns FALSE if this is not a valid call for the supplied // object. If return code is TRUE then check bVisible. BOOL TVisualFramework::IsTabVisible(TVisualObject *pObject, BOOL& bVisible) { ASSERT(pObject); ASSERT(pObject->m_pWnd); ASSERT(pObject->m_pParent); if (pObject->m_pParent->IsKindOf(RUNTIME_CLASS(TTabWnd))) { TTabWnd *pTab = (TTabWnd*)pObject->m_pParent; int nIndex = pTab->GetTabIndex(pObject->m_pWnd); bVisible = pTab->IsTabVisible(nIndex); return TRUE; } return FALSE; } // This should be called from CWinApp derived PreTranslateMessage to handle // any framework related messages BOOL TVisualFramework::ProcessMessage(MSG *pMsg) { ASSERT(pMsg); if (pMsg->message == WM_KEYDOWN) { // Handle Ctrl+Tab for tab windows if (m_bEnableCtrlTab) { if ((pMsg->wParam == VK_TAB) && (::GetAsyncKeyState(VK_CONTROL) != 0)) { CWnd *pWnd = CWnd::FromHandle(pMsg->hwnd); ASSERT(pWnd); if (pWnd->IsKindOf(RUNTIME_CLASS(CFrameWnd))) return FALSE; // If we are in form view then pWnd is a control while (pWnd && !pWnd->IsKindOf(RUNTIME_CLASS(CView))) pWnd = pWnd->GetParent(); // Find object for this window ASSERT(pWnd); TVisualObject *pObject = findObject(pWnd); ASSERT(pObject != NULL); while (pObject && !pObject->m_pWnd->IsKindOf(RUNTIME_CLASS(TTabWnd))) pObject = pObject->m_pOwner; if (pObject) { TTabWnd *pTab = (TTabWnd*)pObject->m_pWnd; BOOL bShift = (::GetAsyncKeyState(VK_SHIFT) != 0); int nIndex = pTab->GetTabIndex(); int nNdx = nIndex; // Switch to new pane (skip invisible and disabled) do { if (bShift) { // Does not work nNdx--; if (nNdx < 0) nNdx = pTab->GetTabCount()-1; } else { nNdx ++; if (nNdx == pTab->GetTabCount()) nNdx = 0; } } while (!pTab->SetActivePane(nNdx) && (nNdx != nIndex)); return TRUE; } } } } else if (pMsg->message == WM_SYSKEYDOWN) { // Handle hot keys for views (if defined) TVisualObject *pObject; TVisualObjectMap::iterator mapit; for (mapit = m_ObjectMap.begin(); mapit != m_ObjectMap.end(); mapit ++) { pObject = mapit->second; if (pObject->m_cHotKey == pMsg->wParam) { if (SetActivePane(pObject)) return TRUE; } } } return FALSE; } BOOL TVisualFramework::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo) { // TODO: Add your specialized code here and/or call the base class return CCmdTarget::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo); } //============================================================================= // class TVisualFormView // // This class implements the code to set the font for all child controls. // If it belongs to the visual framework (as a pane) then setting the font // for the framework's panes will automatically set the font for all child // controls in the form view. //============================================================================= static BOOL __stdcall setChildFont(HWND hwnd, LPARAM lparam); static BOOL __stdcall setChildEnabled(HWND hwnd, LPARAM lparam); IMPLEMENT_DYNAMIC(TVisualFormView, CFormView) BEGIN_MESSAGE_MAP(TVisualFormView, CFormView) //{{AFX_MSG_MAP(TVisualFormView) ON_WM_ENABLE() //}}AFX_MSG_MAP END_MESSAGE_MAP() TVisualFormView::TVisualFormView(LPCTSTR lpszTemplateName) : CFormView(lpszTemplateName) { } TVisualFormView::TVisualFormView(UINT nIDTemplate) : CFormView(nIDTemplate) { } void TVisualFormView::SetFont(CFont *pFont) { ASSERT(pFont); ::EnumChildWindows(m_hWnd, ::setChildFont, (LPARAM)pFont); } void TVisualFormView::OnEnable(BOOL bEnable) { CFormView::OnEnable(bEnable); ::EnumChildWindows(m_hWnd, ::setChildEnabled, (LPARAM)bEnable); } // lParam is a pointer to CFont object BOOL __stdcall setChildFont(HWND hwnd, LPARAM lparam) { CFont *pFont = (CFont*)lparam; ASSERT(pFont); CWnd *pWnd = CWnd::FromHandle(hwnd); ASSERT(pWnd); pWnd->SetFont(pFont); return TRUE; } // lParam is a BOOL BOOL __stdcall setChildEnabled(HWND hwnd, LPARAM lparam) { BOOL bEnabled = (BOOL)lparam; CWnd *pWnd = CWnd::FromHandle(hwnd); ASSERT(pWnd); pWnd->EnableWindow(bEnabled); return TRUE; } /*############################################################################# # End of file VISUALFX.CPP #############################################################################*/